We create an ADM2-year panel to study the effect of climate aid arrival on pollution outcomes from EDGAR. Treatment is defined as first year a climate project occurs in an ADM2 (staggered adoption). Outcome is the ADM2-area-weighted pollution mean.
yvar <-if ("pollution_CO2_log"%in%names(base_panel)) "pollution_CO2_log"else"pollution_CO2_w"run_csdid <-function(base_panel, adopt_tbl, label, min_e =-5, max_e =20) { P <-merge(base_panel[, .(adm2_id, year, y =get(yvar))], adopt_tbl, by ="adm2_id", all.x =TRUE)# Treated flags & event time P[, treated :=as.integer(!is.na(g) & year >= g)] P[, rel_time :=ifelse(is.na(g), NA_integer_, year - g)] P[, adm2_id_int :=as.integer(factor(adm2_id))]# Drop missing outcome and units treated in first overall year min_year <-min(P$year, na.rm =TRUE) D <- P[!is.na(y) & (is.na(g) | g > min_year)]if (nrow(D[!is.na(g)]) ==0L) {warning(sprintf("No treated units for %s — skipping.", label))return(NULL) } att <- did::att_gt(yname ="y",tname ="year",idname ="adm2_id_int",gname ="g",data = D,panel =TRUE, # repeated cross-sections at ADM2-yearcontrol_group ="notyettreated",allow_unbalanced_panel =TRUE )list(label = label,att = att,es = did::aggte(att, type ="dynamic", min_e = min_e, max_e = max_e),grp = did::aggte(att, type ="group") )}
4 CS DiD
We identify the first year in which an ADM2 receives at least one climate project. If the GODAD file already has an ADM2 code, we use it; if not, we perform a spatial join using the point geometry.
library(ggplot2)# Cohort histogram (first g per ADM2)cohort_sizes <- adopt_climate[!is.na(g), .N, by = g][order(g)]cohort_sizes%>%filter(g>=2000)%>%ggplot(aes(g, N)) +geom_col() +labs(title ="Cohort size by first treatment year (All climate)",x ="First project year (g)", y ="ADM2 count") +theme_classic(base_size =12)
Show code
# Cumulative treated share over time# Cumulative treated share = fraction of ADM2 whose g <= yearshare_treated <- descP[!is.na(g), .(share =mean(g <= year)), by = year]# Also include never-treated in denominatorall_ids <-unique(descP$adm2_id)total_n <-length(all_ids)share_treated <- descP[, .(share =mean(!is.na(g) & g <= year)), by = year]ggplot(share_treated, aes(year, share)) +geom_line() +geom_point() +scale_y_continuous(labels = scales::percent) +labs(title ="Share of ADM2 ever treated (cumulative)",x =NULL, y =NULL) +theme_classic(base_size =12)
5.0.4 Outcome distributions & time trends
Show code
# Density of log outcome overallggplot(descP[!is.na(pollution_CO2_log)], aes(pollution_CO2_log)) +geom_density() +labs(title ="Distribution of log(1+CO₂) across ADM2-years",x ="pollution_CO2_log", y ="Density") +theme_classic(base_size =12)
Show code
# Density by ever-treated statusggplot(descP[!is.na(pollution_CO2_log)],aes(pollution_CO2_log, fill =factor(ever_treated))) +geom_density(alpha =0.35) +scale_fill_discrete(name ="Ever treated") +labs(title ="Distribution of log(1+CO₂) by ever-treated status",x ="pollution_CO2_log", y ="Density") +theme_classic(base_size =12)
Show code
# Mean log outcome over time by ever-treated statusmean_by_year <- descP[!is.na(pollution_CO2_log), .(y =mean(pollution_CO2_log, na.rm =TRUE)), by = .(year, ever_treated)]ggplot(mean_by_year, aes(year, y, color =factor(ever_treated))) +geom_line() +geom_point(size =0.9) +labs(title ="Mean log(1+CO₂) over time",color ="Ever treated", x =NULL, y ="Mean log(1+CO₂)") +theme_classic(base_size =12)
5.0.5 Raw event-time mean (not causal; descriptive)